--[[ - Made by Tronex - 2019/7/3 - Global functions for dominance tasks, with support for pre-info before accepting - Dominance tasks target all squads of specified factions in a specified level Parameters for precondition P[1] = (string) task_id P[2] = (num) minimum number of enemy squads in level P[3] = (num) minumum stay time for squad P[4] = (bool) if true, scan will includes scripted squads Example of usage in configs: precondition = validate_dominance_task( mil_smart_terrain_7_7_freedom_leader_stalker_task_2 : 3 : nil : true ) target_functor = dominance_task_target_functor status_functor = dominance_task_status_functor status_functor_params = dolg status_functor_level = jupiter on_job_descr = %=setup_dominance_task( mil_smart_terrain_7_7_freedom_leader_stalker_task_2 )% --]] -- Cache on setup local cache = {} local cache_scripted = {} -- Cache during task local cache_info = {} local cache_func = {} local cache_level = {} local cache_smarts = {} local sfind = string.find local factions_list = { -- List of allowed factions ["stalker"] = true, ["dolg"] = true, ["freedom"] = true, ["csky"] = true, ["ecolog"] = true, ["killer"] = true, ["army"] = true, ["bandit"] = true, ["monolith"] = true, ["renegade"] = true, ["greh"] = true, ["isg"] = true, } ---------------------------< Utility >--------------------------- function is_legit_mutant_squad(squad) local section = squad and squad:section_name() return squad and (not sfind(section,"tushkano")) and (not sfind(section,"rat")) and true or false end function evaluate_smarts_squads(task_id, tbl, smart, squad_def, faction_def) if (not smart) then return end local smrt_id = smart.id local smrt_name = smart:name() local smrt = smrt_id and SIMBOARD.smarts[smrt_id] if (not smrt) then return end --printf("~ %s | scanning smart: %s", task_id, smrt_name) for sq_id,_ in pairs(smrt.squads) do --printf("# %s | found squad (%s) in smart: %s", task_id, sq_id, smrt_name) -- if smart's squad is on its level + they are targeting it local squad = alife_object(sq_id) if squad and simulation_objects.is_on_the_same_level(squad, smart) and squad.current_target_id and (squad.current_target_id == smrt_id) and (squad.current_action == 1) and squad.stay_time and ((not squad_def.stay_time) or (squad_def.stay_time and (game.get_game_time():diffSec(squad.stay_time) <= tonumber(squad_def.stay_time)))) and (squad_def.scripted or (not squad:get_script_target())) then --printf("# %s | smart (%s) [%s] w/ squad (%s) [%s] = Checking", task_id, smrt_id, smrt_name, sq_id, squad.player_id) for fac,_ in pairs(faction_def) do -- if squad is from enemies table if (is_legit_mutant_squad(squad) and squad.player_id == fac) then --squad.stay_time = game.get_game_time() tbl[#tbl + 1] = sq_id --printf("- %s | smart (%s) [%s] w/ squad (%s) [%s] = Added", task_id, smrt_id, smrt_name, sq_id, squad.player_id) end end end end end function evaluate_squads_smarts(task_id, scripted, smart, smrt) for sq_id,_ in pairs(smrt.squads) do local squad = alife_object(sq_id) if squad and simulation_objects.is_on_the_same_level(squad, smart) then if not ( squad.first_update ) then --printf("~ %s | not all squads are loaded yet!", task_id) return true end if (scripted or (not squad:get_script_target())) and (squad.current_target_id and squad.current_target_id == smart.id and squad.current_action == 1) then --printf("- %s | squad (%s) [%s] is targeting smart (%s)", task_id, squad.id, squad.player_id, smart.id) for i = 1, #cache_func[task_id] do local fac = cache_func[task_id][i] if (is_legit_mutant_squad(squad) and squad.player_id == fac) then -- reset gametime so they don't leave squad.stay_time = game.get_game_time() squad.force_online = true --printf("- %s | squad (%s) [%s] is saved", task_id, squad.id, squad.player_id) return sq_id end end end end end return false end function postpone_for_next_frame(task_id, community, lvl) -- Location local str_location = game.translate_string("st_location") .. " " .. lvl -- Community local str_comm = "" if is_squad_monster[community] then str_comm = game.translate_string("st_sq_type") .. " " .. game.translate_string(community) else str_comm = game.translate_string("st_mm_new_game_faction_2") .. " " .. game.translate_string(community) end -- Build News local news_caption = game.translate_string(task_manager.task_ini:r_string_ex(task_id, "title")) or "error" local news_text = str_comm .. "\\n " .. str_location local news_ico = news_manager.tips_icons[community] or task_manager.task_ini:r_string_ex(task_id, "icon") or "ui_iconsTotal_mutant" db.actor:give_talk_message2(news_caption, news_text, news_ico, "iconed_answer_item") return true end ---------------------------< Target functor >--------------------------- task_functor.dominance_task_target_functor = function (task_id,field,p,tsk) if (field == "target") then if (tsk and tsk.stage == 1 and tsk.task_giver_id) then return tsk.task_giver_id end return cache_info[task_id] end end ---------------------------< Status functor >--------------------------- task_status_functor.dominance_task_status_functor = function (tsk,task_id) if not (db.actor and tsk) then return end if (tsk.stage == 1) then return end -- already completed -- Store factions parameters for the first time to re-use it if (not cache_func[task_id]) then local n = 0 cache_func[task_id] = {} local params = parse_list(task_manager.task_ini,task_id,"status_functor_params") for i=1,#params do if is_squad_monster[params[i]] or factions_list[params[i]] then n = n + 1 cache_func[task_id][n] = params[i] printf("/ %s | Faction [%s] is re-added to cache_func table", task_id, params[i]) end end if (#cache_func[task_id] == 0) then printe("! %s | no enemy factions found",task_id) return "fail" end end -- Cache target level cache_level[task_id] = cache_level[task_id] or task_manager.task_ini:r_string_ex(task_id,"status_functor_level") -- Cache smarts if (not cache_smarts[task_id]) then cache_smarts[task_id] = {} local n = 0 local sim = alife() local gg = game_graph() for name,v in pairs(SIMBOARD.smarts_by_names) do -- if smart is available if (simulation_objects.available_by_id[v.id] == true) then local lvl = sim:level_name(gg:vertex(v.m_game_vertex_id):level_id()) if (lvl == cache_level[task_id]) then n = n + 1 cache_smarts[task_id][n] = name end end end end if (not cache_smarts[task_id]) then printe("! %s | no smarts found for level",task_id, cache_level[task_id]) return "fail" end -- Timer for less pressure local tg = time_global() if (tsk.__check_smart_time and tg < tsk.__check_smart_time) then return end tsk.__check_smart_time = tg + 3000 local scripted = load_var(db.actor, task_id) -- check saved data for i=1,#cache_smarts[task_id] do local smart_name = cache_smarts[task_id][i] local smrt_n = SIMBOARD.smarts_by_names[smart_name] local smrt_v = smrt_n and SIMBOARD.smarts[smrt_n.id] -- in case sim_avail is set true during the player's tsk. with simulation_objects.available_by_id[smart.id] nil means unprocess if (simulation_objects.available_by_id[smrt_n.id] == nil) then return end if smrt_v then local squad_id = evaluate_squads_smarts(task_id, scripted, smrt_n, smrt_v) if squad_id == true then return end if squad_id then cache_info[task_id] = squad_id return end end end -- Assuming no squads means that target smarts got cleared tsk.stage = 1 end ---------------------------< Precondition >--------------------------- xr_conditions.validate_dominance_task = function(actor, npc, p) if not (p and #p >= 1) then return false end local task_id = p[1] if (#p < 4) then printe("! %s | not enough parameters", task_id) return false end --// Check cache if cache[task_id] then local tt = cache[task_id] for i=1, #tt do local c_squad_id = tt[i] local c_squad = alife_object(c_squad_id) if c_squad then printf("! %s | reused cache", task_id) return true end end end --// Utilities local is_avail = simulation_objects.available_by_id local p_status = parse_list(task_manager.task_ini,task_id,"status_functor_params") local enemy_faction_list = {} if (not p_status[1]) then printe("! %s | status functor parameters are mising!", task_id) return false end --// Defines local def = {} def.num = tonumber(p[2]) or 1 def.stay_time = (p[3] ~= "nil") and tonumber(p[3]) def.scripted = (p[4] == "true") and true or false def.level = task_manager.task_ini:r_string_ex(task_id,"status_functor_level") if (not def.level) then printe("! %s | status_functor_level is mising!", task_id) return false end cache_scripted[task_id] = def.scripted --// Collect enemy factions for i=1,#p_status do if is_squad_monster[p_status[i]] or factions_list[p_status[i]] then --printf("/ %s | Faction [%s] is added to enemy_faction_list table", task_id, p_status[i]) enemy_faction_list[p_status[i]] = true end end if is_empty(enemy_faction_list) then printf("! %s | no enemy factions found", task_id) return false end --// Search all smarts inside level local sim = alife() local gg = game_graph() local targets = {} for name,v in pairs(SIMBOARD.smarts_by_names) do -- if smart is available if (is_avail[v.id] == true) then local lvl = sim:level_name(gg:vertex(v.m_game_vertex_id):level_id()) if (lvl == def.level) then evaluate_smarts_squads(task_id, targets, v, def, enemy_faction_list) end end end --// Cache results if (#targets >= def.num) then cache[task_id] = {} copy_table(cache[task_id], targets) printf("- %s | %s squads has been found in level (%s)", task_id, size_table(targets), def.level) return true end --printf("! %s | no targets found: %s", task_id, #targets) return false end ---------------------------< Effects >--------------------------- xr_effects.setup_dominance_task = function(actor, npc, p) local task_id = p[1] if not (task_id and cache[task_id]) then printe("! %s | missing info in setup_dominance_task", task_id) return false end --// Read cache local targets = cache[task_id] if (not targets) then printe("! %s | missing cache in setup_dominance_task", task_id) return false end for i=1, #targets do local squad_id = targets[i] local squad = alife_object(squad_id) if squad then squad.stay_time = game.get_game_time() sim_offline_combat.task_squads[squad_id] = true end end local p_status = parse_list(task_manager.task_ini,task_id,"status_functor_params") local lvl = task_manager.task_ini:r_string_ex(task_id,"status_functor_level") --// Save var local scripted = cache_scripted[task_id] and true or false save_var(db.actor, task_id, scripted) printdbg("- %s | Cached result = faction to target: %s - level: %s - current target squads: %s - scripted: %s", task_id, p_status[1], lvl, #targets, scripted) CreateTimeEvent(0, "setup_assault_task", 0, postpone_for_next_frame, task_id, p_status[1], lvl) end